package cgl.narada.samples.security;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.TimeZone;

import cgl.narada.discovery.topics.Entity;
import cgl.narada.discovery.topics.TopicDiscoveryClient;
import cgl.narada.discovery.topics.Topics;
import cgl.narada.discovery.topics.messages.SignedTopicAdvertisement;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.service.security.kmc.KMCClient;
import cgl.narada.service.security.kmc.SignedSecurityToken;
import cgl.narada.service.security.kmc.TopicRights;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;

//HG: Added security stuff to original code by Hasan bulut

public class SecureTopicsKeyGenerator {

    public String host = "localhost", port = "25000", protocol = "niotcp";

    public SecureTopicsKeyGenerator(String data, String control, String a,
            String h, String p, String pr) {
        topicNameData = data;
        topicNameControl = control;
        alias = a;
        initKeyStore("C:\\Home\\tmp\\narada\\keystore\\NBSecurityTest.keys");

        if (h != null)
            host = h;
        if (p != null)
            port = p;
        if (pr != null)
            protocol = pr;
    }

    public String topicUUIDData, topicUUIDControl;
    public String topicNameData, topicNameControl;
    public SecureTopicKeyResponse stkData, stkControl;
    public PublicKey rootCA;
    public Certificate c_cert;
    public PrivateKey c_priv;

    private String alias;

    private void initKeyStore(String keystore) {
        CertificateManager certMan = new CertificateManager();
        certMan.init(keystore, null);

        rootCA = CertificateUtil.getPublicKey(certMan, certMan.ROOT_CA_ALIAS);

        c_cert = CertificateUtil.getCertificate(certMan, alias);
        c_priv = CertificateUtil.getPrivateKey(certMan, alias);
    }

    public void genTopicsAndKeys() {
        // KMCClient client2 = new KMCClient(c_cert, c_priv, rootCA,
        // "/kmc/c2",
        // "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt");
        KMCClient client2 = new KMCClient(c_cert, c_priv, rootCA, "/kmc/"
                + alias, "c:\\Home\\NB1rc1\\config\\ServiceConfiguration.txt",
                host, port, protocol);

        // === FOR DATA ===

        // First discover the topic...
        SignedTopicAdvertisement[] stasD = discoverTopics(c_cert, c_priv,
                topicNameData, Topics.MATCHING_STRING, 1);

        TopicRights reqRightsD = new TopicRights(TopicRights.SUBSCRIBE_RIGHT);

        // Now try to get the security token...
        stkData = client2.requestTopicKey(stasD[0].getTopicAd()
                .getTopicSynopsis(), c_cert, reqRightsD, 5000);

        if (stkData == null)
            System.out.println("Request Denied / Timeout occurred !");
        else {
            System.out.println("Sec Token:"
                    + stkData.getSignedSecurityToken().getSecurityToken()
                            .getValidity().toString());

            topicUUIDData = stasD[0].getTopicAd().getTopicSynopsis();

        }

        // === -x- ===

        // === FOR CONTROL ===

        // First discover the topic...
        SignedTopicAdvertisement[] stasC = discoverTopics(c_cert, c_priv,
                topicNameControl, Topics.MATCHING_STRING, 2);

        TopicRights reqRightsC = new TopicRights(TopicRights.SUBSCRIBE_RIGHT
                + TopicRights.PUBLISH_RIGHT);

        // Now try to get the security token...
        stkControl = client2.requestTopicKey(stasC[0].getTopicAd()
                .getTopicSynopsis(), c_cert, reqRightsC, 5000);

        if (stkControl == null)
            System.out.println("Request Denied / Timeout occurred !");
        else {
            System.out.println("Sec Token:"
                    + stkControl.getSignedSecurityToken().getSecurityToken()
                            .getValidity().toString());

            topicUUIDControl = stasC[0].getTopicAd().getTopicSynopsis();

        }

        // === -x- ===

        client2.close();
    }

    public SignedTopicAdvertisement[] discoverTopics(Certificate cert,
            PrivateKey priv, String synopsis, int matchType, int maxTopics) {

        // TopicDiscoveryClient disco = new TopicDiscoveryClient(
        // 15000,
        // "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt",
        // cert, priv, "complexity.ucs.indiana.edu", "25000", "niotcp");

        TopicDiscoveryClient disco = new TopicDiscoveryClient(15000,
                "c:\\Home\\NB1rc1\\config\\ServiceConfiguration.txt", cert,
                priv, host, port, protocol);

        SignedTopicAdvertisement[] stas = disco.discover(matchType, synopsis,
                null, maxTopics);

        disco.close();

        return stas;
    }

    Entity e;
    KMCClient client;

    public void generateTopics(String algo, int keylen, int timeoutMins1,
            int timeoutMins2) {

        Calendar until1 = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
        until1.add(Calendar.MINUTE, timeoutMins1);

        Calendar until2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
        until2.add(Calendar.MINUTE, timeoutMins2);

        // e = new Entity(
        // 9999,
        // "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt",
        // "c1", c1_cert, c1_priv, rootCA, "complexity.ucs.indiana.edu",
        // "25000", "niotcp");

        e = new Entity(9999,
                "c:\\Home\\NB1rc1\\config\\ServiceConfiguration.txt", alias,
                c_cert, c_priv, rootCA, host, port, protocol);

        if (e.sendTDNDiscoveryRequest(10000)) {
            System.out.println("Found TDN ! Proceeding to create TOPIC !!");
        } else {
            System.out
                    .println("NO TDN found within specified timeout period !!");
        }

        // client = new KMCClient(c1_cert, c1_priv, rootCA, "/kmc/c1",
        // "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt");

        client = new KMCClient(c_cert, c_priv, rootCA, "/kmc/" + alias,
                "c:\\Home\\NB1rc1\\config\\ServiceConfiguration.txt", host,
                port, protocol);

        stkData = createTopicAndSecurityToken(until1, until1, until2,
                topicNameData, algo, keylen, true);
        stkControl = createTopicAndSecurityToken(until1, until1, until2,
                topicNameControl, algo, keylen, false);

        e.close();
        client.close();
    }

    private SecureTopicKeyResponse createTopicAndSecurityToken(Calendar until,
            Calendar until1, Calendar until2, String topicName, String algo,
            int keylen, boolean dataTopic) {

        if (e == null) {
            System.out.println("ERRRORRRR !!!!");
            return null;
        }

        createTopic(e, topicName, TemplateProfileAndSynopsisTypes.STRING, until);

        // Get Signed Topic Ad
        SignedTopicAdvertisement sta = e.getSignedTopicAdvertisement(topicName);

        if (dataTopic) {
            topicUUIDData = sta.getTopicAd().getTopicSynopsis();
        } else
            topicUUIDControl = sta.getTopicAd().getTopicSynopsis();

        // Set the access control lists
        Hashtable pubs = new Hashtable();
        pubs.put(((X509Certificate) c_cert).getSubjectDN().getName(), until);
        if (topicName.startsWith("Media/Control")) {
            pubs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until1);
            pubs.put("CN=client3, OU=CGL, O=IU, L=Bloomington, C=US", until2);
        }

        Hashtable subs = new Hashtable();
        subs.put(((X509Certificate) c_cert).getSubjectDN().getName(), until);
        subs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until1);
        subs.put("CN=client3, OU=CGL, O=IU, L=Bloomington, C=US", until2);

        // Ok, now register the topic and get a security token
        SecureTopicKeyResponse resp = client.registerTopic(pubs, subs, sta,
                c_cert, until, algo, keylen, 5000);

        // Check the response
        SignedSecurityToken tok = resp.getSignedSecurityToken();
        System.out.println("VERIFICATION: " + tok.verify());
        System.out.println("Publish: "
                + tok.getSecurityToken().getRights().hasPublishRight());
        System.out.println("Subscribe: "
                + tok.getSecurityToken().getRights().hasSubscribeRight());

        return resp;
    }

    public boolean createTopic(Entity e, String topicName, int topicType,
            Calendar until) {

        if (!e.createTopic("SELF", until, "Test Topic", topicType, topicName,
                null, 5000)) {
            System.err.println("Could not create topic ! Aborting...");
            return false;
        }

        System.out.println("TOPIC Created: UUID -> "
                + e.getTopicUUID(topicName));
        return true;

    }
}